﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using RQX.Common.Core.Extension;
using RQX.Common.Core.Hardware.BaseCollection;
using RQX.Common.Core.Hardware.Net;
using RQX.Common.Core.Logger;

namespace BLT_HL7SDK
{
    public class HL7SDK : AbstractTcpClientDelegateCollection
    {
        private static PARAM_DATA pParamData = new PARAM_DATA();
        private static int size = Marshal.SizeOf(pParamData);
        private static HL7SDK_INTERFACE HL7Interface = new HL7SDK_INTERFACE();
        private static IntPtr pCallBack = Marshal.AllocHGlobal(Marshal.SizeOf(HL7Interface));
        private static Mutex mutex = new Mutex(false);
        private static byte[] recvBuffer = new byte[0];
        private static bool IsDealSource = false;
        private string objIP;
        public override string IP => "127.0.0.1";

        public override int Port => 0;
        public override DeviceType DeviceType => DeviceType.监护仪;
        public HL7SDK() { }
        public HL7SDK(StructureModel<TcpSocketClient> structureModel) : base(structureModel)
        {
            objIP = structureModel.Ext1?.ToString();
        }

        protected override string CutToOneMsg(StringBuilder sb) => sb.ToString();
        protected override StepType CheckRecvMsgType(string lineStr) => StepType.DataSource;
        protected override void CircleSend() { }
        protected override void Connect(StepType stepNum, string msg = "")
        {
            IsDealSource = true;
            BeginRecv();
            var serIP = (uint)IPAddress.HostToNetworkOrder((int)IPAddress.Parse(objIP).Address);
            var localIP = (uint)IPAddress.HostToNetworkOrder((int)IPAddress.Parse(objIP).Address);

            HL7Interface.OnConnect = new OnConnectDelgate((bedNo) => WriteRecvLogMethod($"已连接！编号：{bedNo}"));
            HL7Interface.OnRecvMonitorData = new OnRecvMonitorDataDelgate(OnRecvMonitorDataFunc);
            HL7Interface.OnDisconnect = new OnDisconnectDelgate((num) =>
            {
                IsDealSource = false;
                WriteRecvLogMethod($"链接已关闭！{num}");
            });

            Marshal.StructureToPtr(HL7Interface, pCallBack, true);
            var a = HL7SDK_Model.InitHL7SDK(pCallBack, HL7_WORK_MODE.HL7_MODE_SERVER_MONITOR, serIP, localIP);
            WriteRecvLogMethod($"开始连接:{a}");
        }

        private void BeginRecv()
        {
            Task.Run(() =>
            {
                while (IsDealSource)
                {
                    Thread.Sleep(1000);
                    try
                    {
                        mutex.WaitOne();
                        if (recvBuffer.Length > 0)
                        {
                            RecvData(recvBuffer);
                            recvBuffer = new byte[0];
                        }
                    }
                    catch (Exception ex)
                    {
                        LogUtils.WriteErrorLog($"处理数据异常！{ex}", "127.0.0.1");
                    }
                    finally
                    {
                        mutex.ReleaseMutex();
                    }
                }
            });
        }

        protected override Dictionary<string, string> AnalysisData(string msg)
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            try
            {
                var m_curRecvBuf = msg.HexStringToByte();
                var count = m_curRecvBuf.Length / size;
                for (int i = 0; i < count; i++)
                {
                    byte[] buffer = new byte[size];
                    Array.Copy(m_curRecvBuf, i * size, buffer, 0, size);
                    pParamData = (PARAM_DATA)BytesToStruct(buffer, pParamData.GetType());
                    var modelId = pParamData.wModuleID;
                    var paramId = pParamData.wParamID;
                    var name = pParamData.strName;
                    var value = pParamData.dwValue;
                    WriteDebugLogMethod($"{modelId}\t{paramId}\t{name}\t{value}");
                    switch ($"{modelId}_{paramId}")
                    {
                        case "1_0"://ECG    HR
                        case "2_0"://SpO2   SpO2
                        case "2_1"://SpO2   PR
                        case "3_0"://NIBP   SYS
                        case "3_2"://NIBP   DIA
                        case "4_0"://RESP   RR
                        case "5_0"://CO2    EtCO2
                        case "7_0"://BIS    BIS
                        case "9_1"://O2     FiO2
                        case "22_0"://ART   SYS
                        case "22_2"://ART   DIA
                        case "23_0"://CVP   SYS
                        case "23_2"://CVP   DIA
                            dic.Add(name, value.ToString());
                            break;
                    }
                    //switch (pParamData.strName)
                    //{
                    //    case "HR":
                    //    case "SpO2":
                    //    case "NIBPs":
                    //    case "NIBPm":
                    //    case "NIBPd":
                    //    case "Resp":
                    //    default:
                    //        dic.Add(pParamData.strName, pParamData.dwValue.ToString());
                    //        break;
                    //    case "P1s":
                    //    case "P2s":
                    //    case "P1m":
                    //    case "P2m":
                    //    case "P1d":
                    //    case "P2d":
                    //        dic.Add(pParamData.strName, (pParamData.dwValue - 200).ToString());
                    //        break;
                    //    case "T1":
                    //    case "T2":
                    //        dic.Add(pParamData.strName, ((pParamData. ) / 100.0).ToString());
                    //        break;
                    //        //this.tbTEMP.Text = (Convert.ToDouble(this.tbTEMP1.Text) - Convert.ToDouble(this.tbTEMP2.Text)).ToString();
                    //}
                }
            }
            catch (Exception ex)
            {
                LogUtils.WriteErrorLog($"AnalysisData:{ex}", objIP);
            }
            var items = dic.Where(k => k.Value.Equals("-100") || k.Value.Equals("-32569"));
            if (items.Count() > 0)
            {
                var deleteList = items.Select(k => new KeyValuePair<string, string>(k.Key, k.Value));
                WriteAnalysisLogMethod(items);
                deleteList.ToList().ForEach(item => dic.Remove(item.Key));
            }
            return dic;
        }
        public void OnRecvMonitorDataFunc(int iBedNO, IntPtr pData, int length, int iDataType)
        {
            if (iDataType == (int)HL7_MSG_TYPE.HL7_MSG_PARAM_DATA)
            {
                try
                {
                    mutex.WaitOne();
                    if (length > 0)
                    {
                        recvBuffer = new byte[length];
                        Marshal.Copy(pData, recvBuffer, 0, length);
                    }
                }
                catch (Exception ex)
                {
                    LogUtils.WriteErrorLog($"接收数据异常！{ex}", "127.0.0.1");
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
        }

        /// <summary>
        /// 字节数组转换成结构
        /// </summary>
        /// <param name="bytes">要转换的byte数组</param>
        /// <param name="type">转换后的结构对象</param>
        /// <returns></returns>
        public static object BytesToStruct(byte[] bytes, Type type)
        {
            //得到结构的大小
            int size = Marshal.SizeOf(type);
            //Log(size.ToString(), 1);

            //byte数组长度小于结构的大小
            if (size > bytes.Length) return null;

            //分配结构大小的内存空间
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            //将byte数组拷到分配好的内存空间
            Marshal.Copy(bytes, 0, structPtr, size);
            //将内存空间转换为目标结构
            object obj = Marshal.PtrToStructure(structPtr, type);
            //释放内存空间
            Marshal.FreeHGlobal(structPtr);
            //返回结构
            return obj;
        }
    }
}
